package com.bluedot.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bluedot.controller.DistributeClass;
import com.bluedot.pojo.pack.FileResponse;
import com.bluedot.pojo.pack.PreMappedStatement;
import com.bluedot.pojo.pack.ResultEntity;
import com.bluedot.pojo.po.*;
import com.bluedot.pojo.vo.*;
import com.bluedot.timer.dataChargeTimer;

import javax.servlet.http.HttpSession;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Stream;

import static com.bluedot.timer.LogTimer.utilTool;

/**
 * @ClassName: DataChargeService
 * @Description: TODO
 * @Author: 初久
 * @Date: 2022/8/15 10:43
 **/
public class DataChargeService extends DistributeClass {

    private final UtilTool util = new UtilTool();

    private PreMappedStatement<String> preMappedStatement;

    public DataChargeService(PreMappedStatement<String> preMappedStatement) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        super(preMappedStatement);
        this.preMappedStatement = preMappedStatement;

        String[] split = preMappedStatement.getMethodType().split("/");
        switch (split[split.length - 1]) {
            case "queryMaterial":
                getResponseQueue().add(ResultEntity.successWithData(queryMaterial()));
                break;
            case "exportMaterialData":
                getResponseQueue().add(ResultEntity.successWithData(exportMaterialData()));
                break;
            case "deleteMaterialLogical":
                deleteMaterialLogical();
                break;
            case "deleteMaterialForever":
                deleteMaterialForever();
                break;
            case "unLogicalDeleteMaterial":
                unLogicalDeleteMaterial();
                break;
            case "queryReport":
                getResponseQueue().add(ResultEntity.successWithData(queryReport()));
                break;
            case "updateReport":
                updateReport();
                break;
            case "deleteReportLogical":
                deleteReportLogical();
                break;
            case "deleteReportForever":
                deleteReportForever();
                break;
            case "unLogicalDeleteReport":
                unLogicalDeleteReport();
                break;
            case "exportReport":
                getResponseQueue().add(ResultEntity.successWithData(exportReport()));
                break;
            case "applyAddMaterialType":
                applyAddMaterialType();
                break;
            case "applyRestoreMaterials":
                applyRestoreMaterials();
                break;
            case "queryUserMaterialsRequests":
                getResponseQueue().add(ResultEntity.successWithData(queryUserMaterialsRequests()));
                break;
            case "addMaterialType":
                addMaterialType();
                break;
            case "deleteMaterialType":
                deleteMaterialType();
                break;
            case "updateMaterialType":
                updateMaterialType();
                break;
            case "queryMaterialType":
                getResponseQueue().add(ResultEntity.successWithData(queryMaterialType()));
                break;
            case "queryMaterialTypeRequests":
                getResponseQueue().add(ResultEntity.successWithData(queryMaterialTypeRequests()));
                break;
            case "examineMaterialTypeRequests":
                examineMaterialTypeRequests();
                break;
            case "adjustRecycle":
                adjustRecycle();
                break;
            case "query-index-data":
                getResponseQueue().add(ResultEntity.successWithData(queryIndexData()));
                break;
            default:
                throw new RuntimeException("url未匹配");
        }
    }

    // 获取研究员首页数据
    private IndexNumVO queryIndexData() {

        // 查询指定Id的实验数据  算法数据  实验报告数据 数量
        HttpSession session = preMappedStatement.getRequest().getSession();
        UserVO user = (UserVO)session.getAttribute("user");
        String userId = user.getUserId();
        IndexNumVO indexNumVO = new IndexNumVO();
        Material material = new Material();
        material.setUserId(userId);

        List<Object> queryOrigin = utilTool.query(new PreMappedStatement<>(UtilTool.QUERY, material));
        indexNumVO.setExperimentNum(queryOrigin == null ? 0 : queryOrigin.size());
        AlgorithmVO algorithmVO = new AlgorithmVO();
        algorithmVO.setUserId(userId);
        List<Object> algorithms = utilTool.query(new PreMappedStatement<>(UtilTool.QUERY, algorithmVO));
        indexNumVO.setAlgorithmNum(algorithms == null ? 0 : algorithms.size());

        ReportVO report = new ReportVO();
        report.setUserId(userId);
        List<Object> reports = utilTool.query(new PreMappedStatement<>(UtilTool.QUERY, report));
        indexNumVO.setReportNum(reports == null ? 0 : reports.size());

        return indexNumVO;
    }

    /**
     * @return java.util.List<java.lang.Object>
     * @Description TODO 查询物质数据信息
     * @MethodName queryMaterial
     * @Param []
     * @Date 2022/8/16 16:15
     **/
    private List<Object> queryMaterial() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
       // Material material = (Material) util.JSONtoObject(preMappedStatement.getData(), Material.class);

        Material material = new Material();
        HttpSession session = preMappedStatement.getRequest().getSession();
        UserVO user = (UserVO)session.getAttribute("user");
        material.setUserId(user.getUserId());
        /*UserVO user = new UserVO();
        user.setUserId("22080007");*/
        MaterialVO materialVO = new MaterialVO();
        materialVO.setUserId(user.getUserId());
        List<Object> queryOrigin = utilTool.query(new PreMappedStatement<>(UtilTool.QUERY, materialVO));
        List<Object> list = new ArrayList<>();
        if(queryOrigin == null || queryOrigin.isEmpty() || queryOrigin.size() == 0){
            return list;
        }

        HashMap<Integer,MaterialVO> map = new HashMap<>();
        for (Object o : queryOrigin) {
            // 同一个物质信息返回最新状态的数据
            MaterialVO a = (MaterialVO) o;
            if(map.containsKey(a.getMaterialId())){
                MaterialVO materialVO1 = map.get(a.getMaterialId());
                if(a.getMaterialState() > materialVO1.getMaterialState()){
                    map.put(a.getMaterialId(),a);
                }
            }else{
                map.put(a.getMaterialId(),a);
            }

        }

        Collection<MaterialVO> values = map.values();

        values.forEach(i -> list.add(i));

        // PreMappedStatement preMappedStatement = new PreMappedStatement(UtilTool.QUERY, Material.class);

        return list;
    }

    /**
     * @return byte[]
     * @Description TODO 导出物质数据信息
     * @MethodName exportMaterialData
     * @Param []
     * @Date 2022/8/16 16:15
     **/
    private FileResponse exportMaterialData() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        MaterialVO materialVO = (MaterialVO) util.JSONtoObject(preMappedStatement.getData(), MaterialVO.class);
        List<Object> resultList = util.query(new PreMappedStatement(UtilTool.QUERY, materialVO));

        StringBuffer stringBuffer = new StringBuffer();
        resultList.forEach(x -> stringBuffer.append(x.toString()));
        return uploadFile(stringBuffer.toString(), "material");
    }

    /**
     * @return void
     * @Description TODO 将物质数据信息移入回收站
     * @MethodName deleteMaterialLogical
     * @Param []
     * @Date 2022/8/16 16:16
     **/
    private void deleteMaterialLogical() {
        for (String data : splitDataStrings()) {
            util.update(new PreMappedStatement(UtilTool.UPDATE, new Material(Integer.parseInt(data), 1)));
        }

    }

    /**
     * @return void
     * @Description TODO 彻底删除物质数据信息
     * @MethodName deleteMaterialForever
     * @Param []
     * @Date 2022/8/16 16:16
     **/
    private void deleteMaterialForever() {
        for (String data : splitDataStrings()) {
            util.delete(new PreMappedStatement(UtilTool.DELETE, new Material(Integer.parseInt(data))));
            util.delete(new PreMappedStatement(UtilTool.DELETE, new MaterialDetail(Integer.parseInt(data))));
        }
    }

    /**
     * @return void
     * @Description TODO 将物质数据信息从回收站移除
     * @MethodName undoLogicalDeleteMaterial
     * @Param []
     * @Date 2022/8/16 16:16
     **/
    private void unLogicalDeleteMaterial() {
        for (String data : splitDataStrings()) {
            util.update(new PreMappedStatement(UtilTool.UPDATE, new Material(Integer.parseInt(data), 0)));
        }
    }

    /**
     * @return java.util.List<java.lang.Object>
     * @Description TODO 查询实验报告
     * @MethodName queryReport
     * @Param []
     * @Date 2022/8/16 16:16
     **/
    private List<ReportVO> queryReport() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        ReportVO report = (ReportVO) util.JSONtoObject(preMappedStatement.getData(), ReportVO.class);
        List<Object> query = util.query(new PreMappedStatement(UtilTool.QUERY, report));

        List<ReportVO> list = new ArrayList<>();
        if(query == null || query.isEmpty() || query.size() == 0){
            return list;
        }

        for (Object o : query) {
            if (o instanceof ReportVO) {
                List<List<String>> trainPointCoordinate = new ArrayList<>();
                List<List<String>> testPointCoordinate = new ArrayList<>();
                ReportVO reportVO = (ReportVO) o;
                String trainSolubility = reportVO.getTrainSolubility();
                String trainPreSolubility = reportVO.getTrainPreSolubility();
                String trainIp = reportVO.getTrainIp();
                String testSolubility = reportVO.getTestSolubility();
                String testPreSolubility = reportVO.getTestPreSolubility();
                String testIp = reportVO.getTestIp();

                reportVO.setTrainIpShow(trainIp.split(","));

                String[] trainSolubilitySplit = trainSolubility.split(",");
                reportVO.setTrainSolubilityShow(trainSolubilitySplit);// 训练集溶度
                String[] trainPreSolubilitySplit = trainPreSolubility.split(",");
                reportVO.setTrainPreSolubilityShow(trainPreSolubilitySplit);// 训练集预测溶度
                for(int i = 0;i < trainSolubilitySplit.length;i ++){
                    if(i < trainPreSolubilitySplit.length){

                        ArrayList<String> list1 = new ArrayList<>();
                        list1.add(trainSolubilitySplit[i]);
                        list1.add(trainPreSolubilitySplit[i]);
                        trainPointCoordinate.add(list1);
                    }

                }
                String[] testSolubilitySplit = testSolubility.split(",");
                reportVO.setTestSolubilityShow(testSolubilitySplit);
                String[] testPreSolubilitySplit = testPreSolubility.split(",");
                reportVO.setTestPreSolubilityShow(testPreSolubilitySplit);

                for(int i = 0;i < testSolubilitySplit.length;i ++){
                    if(i < testPreSolubilitySplit.length)
                        testPointCoordinate.add(Arrays.asList(testSolubilitySplit[i],testPreSolubilitySplit[i]));
                }

                reportVO.setTestPointCoordinate(testPointCoordinate);
                reportVO.setTrainPointCoordinate(trainPointCoordinate);
                reportVO.setTestIpShow(testIp.split(","));
                list.add(reportVO);
            }
        }


        return list;

    }

    /**
     * @return void
     * @Description TODO 更新实验报告
     * @MethodName updateReport
     * @Param []
     * @Date 2022/8/16 16:17
     **/
    private void updateReport() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        String data = preMappedStatement.getData();

        Report report = (Report) util.JSONtoObject(data, Report.class);
        ReportDetail reportDetail = (ReportDetail) util.JSONtoObject(data, ReportDetail.class);

        util.update(new PreMappedStatement(UtilTool.UPDATE, report));
        util.update(new PreMappedStatement(UtilTool.UPDATE, reportDetail));

    }

    /**
     * @return void
     * @Description TODO 将实验报告移入回收站
     * @MethodName deleteReportLogical
     * @Param []
     * @Date 2022/8/16 16:17
     **/
    private void deleteReportLogical() {
        for (String data : splitDataStrings()) {
            util.update(new PreMappedStatement(UtilTool.UPDATE, new Report(Integer.parseInt(data), 1)));
        }
    }

    /**
     * @return void
     * @Description TODO 彻底删除实验报告
     * @MethodName deleteReportForever
     * @Param []
     * @Date 2022/8/16 16:17
     **/
    private void deleteReportForever() {
        for (String data : splitDataStrings()) {
            util.delete(new PreMappedStatement(UtilTool.DELETE, new Report(Integer.parseInt(data))));
            util.delete(new PreMappedStatement(UtilTool.DELETE, new ReportDetail(Integer.parseInt(data))));
        }
    }

    /**
     * @return void
     * @Description TODO 将实验报告移除回收站
     * @MethodName unLogicalDeleteReport
     * @Param []
     * @Date 2022/8/16 16:17
     **/
    private void unLogicalDeleteReport() {
        for (String data : splitDataStrings()) {
            util.update(new PreMappedStatement(UtilTool.UPDATE, new Report(Integer.parseInt(data), 0)));
        }
    }


    /**
     * @return java.io.FileReader
     * @Description TODO 导出实验报告,返回文件的读取流
     * @MethodName exportReport
     * @Param []
     * @Date 2022/8/16 16:17
     **/
    private FileResponse exportReport() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        ReportVO reportVO = (ReportVO) util.JSONtoObject(preMappedStatement.getData(), ReportVO.class);
        List<Object> resultList = util.query(new PreMappedStatement(UtilTool.QUERY, reportVO));

        StringBuffer stringBuffer = new StringBuffer();
        resultList.forEach(x -> stringBuffer.append(x.toString()));
        return uploadFile(stringBuffer.toString(), "report");
    }

    private FileResponse uploadFile(String data, String typeName) {

        String filePath = System.getProperty("user.dir") + File.separatorChar + typeName + File.separatorChar;
        File dir = new File(filePath);
        if (!dir.exists() && !dir.isDirectory()) {
            dir.mkdirs();
        }

        String fileName = data.substring(0, data.indexOf(":")) + "-" + // 分割
                System.currentTimeMillis() + ".txt";
        String allPath = filePath + fileName;

        File file = new File(allPath);
        BufferedWriter bufferedWriter = null;
        try {
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
            bufferedWriter.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufferedWriter != null) {
                try {
                    // 一定要关闭
                    bufferedWriter.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
        // 写入结束

        FileResponse response = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            response = new FileResponse(fileName, inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return response;
    }

    /**
     * @return void
     * @Description TODO 用户申请添加物质类型
     * @MethodName applyAddMaterialType
     * @Param []
     * @Date 2022/8/16 16:20
     **/
    private void applyAddMaterialType() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        RequestVO requestVO = (RequestVO) util.JSONtoObject(preMappedStatement.getData(), RequestVO.class);
        requestVO.setRequestType(2);
        util.insert(new PreMappedStatement(UtilTool.INSERT, requestVO));
    }

    /**
     * @return void
     * @Description TODO 申请恢复物质数据
     * @MethodName applyRestoreMaterials
     * @Param []
     * @Date 2022/8/16 16:15
     **/
    private void applyRestoreMaterials() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        RequestVO requestVO = (RequestVO) util.JSONtoObject(preMappedStatement.getData(), RequestVO.class);
        util.insert(new PreMappedStatement(UtilTool.INSERT, requestVO));
    }

    /**
     * @return java.util.ArrayList<com.bluedot.pojo.RequestVO>
     * @Description TODO 查询所有用户物质数据恢复申请订单
     * @MethodName queryUserMaterialsRequests
     * @Param []
     * @Date 2022/8/18 17:00
     **/
    private List<Object> queryUserMaterialsRequests() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        RequestVO request = (RequestVO) util.JSONtoObject(preMappedStatement.getData(), RequestVO.class);
        return util.query(new PreMappedStatement(UtilTool.QUERY, request));
    }

    /**
     * @return void
     * @Description TODO 调整回收时间
     * @MethodName adjustRecycle
     * @Param []
     * @Date 2022/8/24 22:28
     **/
    private void adjustRecycle() {
        Map req = (Map) JSON.parse(preMappedStatement.getData());
        String s = req.get("time").toString();
        dataChargeTimer.changeSchedule(Long.parseLong(s));
    }

    /**
     * @return void
     * @Description TODO 添加新物质类型
     * @MethodName addMaterialType
     * @Param []
     * @Date 2022/8/19 16:59
     **/
    private void addMaterialType() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        MaterialType materialType = (MaterialType) util.JSONtoObject(preMappedStatement.getData(), MaterialType.class);
        util.insert(new PreMappedStatement(UtilTool.INSERT, materialType));
    }

    /**
     * @return void
     * @Description TODO 删除物质类型信息
     * @MethodName deleteMaterialType
     * @Param []
     * @Date 2022/8/19 17:09
     **/
    private void deleteMaterialType() {
        for (String data : splitDataStrings()) {
            util.delete(new PreMappedStatement(UtilTool.DELETE, new MaterialType(Integer.parseInt(data))));
        }
    }

    /**
     * @return void
     * @Description TODO 修改物质类型信息
     * @MethodName updateMaterialType
     * @Param []
     * @Date 2022/8/19 17:10
     **/
    private void updateMaterialType() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        MaterialType materialType = (MaterialType) util.JSONtoObject(preMappedStatement.getData(), MaterialType.class);
        util.update(new PreMappedStatement(UtilTool.UPDATE, materialType));
    }

    /**
     * @return java.util.List<java.lang.Object>
     * @Description TODO 查询物质类型信息。由于物质数据类型不会很多且不会频繁的修改，所以我这里直接展示所有信息即可
     * @MethodName queryMaterialType
     * @Param []
     * @Date 2022/8/19 17:10
     **/
    private List<Object> queryMaterialType() {
        return util.query(new PreMappedStatement(UtilTool.QUERY, new MaterialType()));
    }

    /**
     * @return java.util.List<java.lang.Object>
     * @Description TODO 展示所有物质类型申请订单
     * @MethodName queryMaterialTypeRequests
     * @Param []
     * @Date 2022/8/19 20:57
     **/
    private List<Object> queryMaterialTypeRequests() {
        return util.query(new PreMappedStatement(UtilTool.QUERY, new RequestVO(2)));
    }

    /**
     * @return void
     * @Description TODO 审核物质类型申请订单,通知由前端调用
     * @MethodName examineMaterialTypeRequests
     * @Param []
     * @Date 2022/8/19 21:06
     **/
    private void examineMaterialTypeRequests() {
        Map req = (Map) JSON.parse(preMappedStatement.getData());
        if ((Integer) req.get("result") == 1) {
            Integer requestId = (Integer) req.get("requestId");
            //更新订单信息
            util.update(new PreMappedStatement(UtilTool.UPDATE, new RequestVO(requestId, (String) req.get("requestHandlerId"), 1)));
            //查询该订单信息然后创建新物质类型到数据库中
            util.query(new PreMappedStatement(UtilTool.QUERY, new RequestVO().setRequestId(requestId))).forEach(x -> {
                //添加新物质类型
                MaterialType type = new MaterialType();
                for (Field field : x.getClass().getDeclaredFields()) {
                    try {

                        if (field.getName().equals("requestContent")) {
                            field.setAccessible(true);
                            type.setMaterialTypeContent((String) field.get(x));
                        }
                        if (field.getName().equals("materialTypeName")) {
                            field.setAccessible(true);
                            type.setMaterialTypeName((String) field.get(x));
                        }

                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                }
                //添加物质类型
                util.insert(new PreMappedStatement(UtilTool.INSERT, new MaterialType(type.getMaterialTypeContent(), type.getMaterialTypeName())));
                // 删除订单信息
                util.delete(new PreMappedStatement(UtilTool.DELETE, new RequestVO().setRequestId(requestId)));
            });
        }
    }

    /**
     * @return java.lang.String[]
     * @Description TODO 分割字符串，返回字符串数组
     * 注意：只能处理单个字段的值数组请求
     * 如：
     * {
     * "materialId":
     * [
     * 3,
     * 26,
     * 21,
     * 13,
     * 14
     * ]
     * }
     * @MethodName splitDataStrings
     * @Param []
     * @Date 2022/8/16 16:37
     **/
    private String[] splitDataStrings() {
        String originalData = preMappedStatement.getData().replaceAll(" ", "");
        originalData = originalData.substring(originalData.indexOf("[") + 1, originalData.indexOf("]"));
        return originalData.split(",");
    }

}
